import { Snowflake } from "api/structures/utils/Snowflake";
import { Message } from "api/structures/Message"
import { getFrom, getBefore } from "api/client/MessageQuery"
import { sendTextMessage } from "api/client/MessageSend"


interface BasicImageAttach {
    filename: string
    url: string
    url_small: string
    small_width: number
    small_height: number
    imageWidth: number
    imageHeight: number
}

interface BasicBinaryAttach {
    filename: string
    url: string
    filesize: number
}

interface BasicChat {
    id: string
    indexCount: number
    chatMessage: string
    userAvatar: string
    nickName: string
    colorName: string
    timeText: number
    isShort: boolean

    textLength: number 

    imageAttachmentAmount: number
    imageAttachments: BasicImageAttach[] 

    binaryAttachmentAmount: number
    binaryAttachments: BasicBinaryAttach[] 
}

// https://blog.basyskom.com/2020/how-to-speedup-your-qt-qml-lists/

declare const listBasicChatModel: Qml.ListModel<BasicChat>;
declare const listBasicChatView: Qml.ListView;
declare const messageField2: Qml.TextField;

let currentChat: string = "";
// let lastMessageId: Snowflake | null = null;
// let lastMessageTimestamp: number = -1;

let lastSender: Snowflake|null = null;
let lastMsgDate: number = 0;

let initialScroll = false;

let loading = false;
let cooldown = false;

let loading_after = false;
let cooldown_after = false;

let index = 0;

export function handleReady(chat_id: string) {
    
    console.log("BasicChat.handleReady")

    window.client.emit("debug", "Chat open " + chat_id)

    currentChat = chat_id;
    // lastMessageTimestamp = -1
    // lastMessageId = null
    lastMsgDate = 0
    lastSender = null

    const channel = window.client.getChannelById(currentChat)
    if (channel?.guild) {


        // Sync request
        // window.client.ws.send({
        //     op:14,
        //     d:{
        //         guild_id: guildId,
        //         typing: true,
        //         threads: true,
        //         activities: true,
        //         members: [],
        //         channels: {},
        //         thread_member_lists: []
        //     }
        // })

        // Channel_Statuses
        // window.client.ws.send({"op":36,"d":{"guild_id":"745037351163527189"}})

        
        // GUILD_MEMBER_LIST_UPDATE
        const tt =  {
            "op":14,
            "d":{
                "guild_id": channel.guild.id,
                "channels":{ 
                    [currentChat]:[
                        [0,99]
                    ]
                }
            }
        }

        window.client.ws.send(tt)
    } else {
        window.client.ws.send({ op: 13,  d: { channel_id: chat_id } })
    }


    // {"op":14,"d":{"guild_id":"745037351163527189","typing":true,"threads":true,"activities":true,"members":[],"channels":{},"thread_member_lists":[]}}
    // {"op":36,"d":{"guild_id":"745037351163527189"}}
    // {"op":8,"d":{"guild_id":["745037351163527189"],"user_ids":["172688063460278272","523886937556385802","693150429403414578","934142261967613982","762678768032546819","665281917431709737","733033008583540776","777006045700161537","145300108567773184","268478587651358721","224235194842873856"],"presences":false}}
    // {"op":28,"d":{"guild_id":"172440238717665280","channel_id":"1020038887910936647","threads":[{"thread_id":"1174878290587172956","ack_message_id":"1175809691239059528"},{"thread_id":"1173246350117326958","ack_message_id":"1173247908854906920"}]}}
    // {"op":14,"d":{"guild_id":"172440238717665280","channels":{"1020038887910936647":[[0,99]],"215496276609990656":[[0,99]]}}}
    // {"op":14,"d":{"guild_id":"745037351163527189","channels":{"745037351725826080":[[0,99]],"745047172952883220":[[0,99]]}}}
    // {"op":14,"d":{"guild_id":"745037351163527189","channels":{"745037351725826080":[[0,99],[100,199]]}}}

    listBasicChatModel.clear();

    loading = true;
    window.client.messageStore.getMessages(chat_id as Snowflake, 30, function(data: string[]){
        loading = false;

        
        console.log("getMessages=" + data.length)
        

        if (!data.length) return

        handleClientReady(data, false)

        initialScroll = true;
    });

    window.client.on("message-new", subscribeToMessages)
}

function handleDestroy() {

    console.log("BasicChat.handleDestroy")

    window.client.off("message-new", subscribeToMessages)
}

// https://regex101.com/r/Rm5S2K/1
// https://regex101.com/r/NX6OU2/3
// https://regexr.com/4h9sh
// /<(?:[^\d>]+|:[A-Za-z0-9]+:)\w+>/g
// /<((@!?&?\d+)|(a?:.+?:\d+))>/g
// /(<(?:[^\d>]+|:[A-Za-z0-9]+:)>)/gm
const urlRegex = /(<?https?:\/\/[^\s]+>?)/g;
const CODE_0 = /```([\S\s]*?)```/gm;
const CODE_1 = /`([\S\s]*?)`/gm;
const DISORD_BRACKETS = /(<(.*?)>)/gm;

function urlify(text: string) {
    return text.replace(urlRegex, (url) => {
        url = url.replace("<", "").replace(">", "")
        return '<a href="' + url + '">' + url + '</a>'
    })
}

function discord_brackets(text: string) {
    return text.replace(DISORD_BRACKETS, (text, patten0, pattern1)=> {
        // console.log("TTTcode_select_0 " + url)
        switch(pattern1.charAt(0)) {
            case "@": 
                const ttt = pattern1.charAt(1) == "!";
                const ttt0 = pattern1.replace(/@?!?/g, "")

                const channel = window.client.getChannelById(currentChat)
                const guildMember = channel?.guild?.members[ttt0]
                const userPrivate = window.client.users[ttt0]

                // console.log("TT", 
                //     ttt0, 
                //     guildMember?.user?.username, 
                //     guildMember?.user?.display_name, 
                //     userPrivate?.username, 
                //     userPrivate?.global_name)

                return "<b>@" + (guildMember?.user?.display_name || userPrivate?.global_name || pattern1)+"</b>"
            case "#":
                return "Channel: " + pattern1
            case ":":
                const [ val1, val2 ] = pattern1.substring(1).split(":")

                return "Emoji: " + pattern1
            default:
                return patten0
        }
    })
}

function code_select_0(text: string) {
    return text.replace(CODE_0, (text, url)=> {
        // console.log("TTTcode_select_0 " + url)
        return '<pre>' + url + '</pre>'
    })
}

function code_select_1(text: string) {
    return text.replace(CODE_1, (text, url)=> {
        // console.log("TTTcode_select_1 " + url)
        return '<pre>' + url + '</pre>'
    })
}

function handleMessage(message: Message) : BasicChat {

    // console.log("chat " + currentChat )
    // console.log("message " + JSON.stringify(message))

    let text = "";
    if (message.content && message.content.length) {
        text = message.content;
    }

    // if (message.attachments.length) {
    //     message.attachments.forEach((element, index) => {
    //         text += "att:" + index + " " + element.filename + " " + element.content_type + ", "
    //     })
    // }

    // if (lastMessageTimestamp==-1 || lastMessageTimestamp>message.timestamp_number) {

    //     lastMessageTimestamp = message.timestamp_number
    //     lastMessageId = message.id
    // }

    let isShort = true 
    
    if (lastSender != message.author.id) {

        lastSender = message.author.id;
        lastMsgDate = message.timestamp_number

        isShort = false
    } else {

        const minutes0 = Math.floor(((message.timestamp_number/1000)/60)/60);
        const minutes1 = Math.floor(((lastMsgDate/1000)/60)/60);
        const diffs = Math.abs(minutes0-minutes1);

        // console.log("Minutes diffs = " + diffs)

        if (diffs > 5 ) {
            lastMsgDate = message.timestamp_number
            isShort = false
        }
    }
    
    const images = message.attachments.filter((data)=>{

        // console.log("images.filter=" + data.filename + " , " + data.content_type)

        if (data.content_type) {
            return data.content_type.indexOf("image/") == 0;
        }

        return false
    })

    const binary  = message.attachments.filter((data)=>{

        // console.log("binary.filter=" + data.filename + " , " + data.content_type)

        if (data.content_type) {
            return data.content_type.indexOf("image/") == -1;
        }

        return !data.content_type
    })

    const channel = window.client.getChannelById(currentChat)

    const guildMember = channel?.guild?.members[message.authod_id]
    
    // console.log("GuildMember " + currentChat + ", " + guildId + ", " + guildMember?.id + ", " + guildMember?.getColor)
    // console.log("   this.roles " + JSON.stringify(guildMember?.roles))

    const color = guildMember?.getColor || "999999"
    
    // const guildChannel = guild?.channels[currentChat]

    // const last_message_id = guildChannel?.last_message_id || channel?.last_message_id 

    // if (message.id == last_message_id) {
    //     text = "last > " + text
    // }

    text = urlify(text);
    text = discord_brackets(text);
    text = code_select_0(text);
    text = code_select_1(text);

    console.log("TTT " + text)
    return {
        id: message.id,
        indexCount: index++,
        userAvatar: message.author.avatarURL,
        chatMessage: text,
        textLength: text.length,
        nickName: message.author.global_name || message.author.username,
        colorName: "#" + color,
        timeText: message.timestamp_number,
        isShort: isShort,
        imageAttachmentAmount: images.length,
        imageAttachments: images.map((data)=>{ 
            return { 
                ...data, 
                imageWidth: data.width, 
                imageHeight: data.height,
                small_width: Math.ceil(data.width*0.13),
                small_height: Math.ceil(data.height*0.13),
                url_small: data.url+"=&format=webp&width=" + Math.ceil(data.width*0.13) + "&height=" + Math.ceil(data.height*0.13)
            }
        }),
        binaryAttachmentAmount: binary.length,
        binaryAttachments: binary.map((data)=> {
            return {
                filename: data.filename,
                url: data.url,
                filesize: data.size
            }
        })
    }
}

function subscribeToMessages(channel_id: string, message: string, last_message_id: string) {

    if (channel_id === currentChat) {



        for (let index = 0; index < listBasicChatModel.count; index++) {
            const currentId = listBasicChatModel.get(index).id;
            console.log("subscribeToMessages " + index + ", " + currentId + ", isLast=" + (currentId == last_message_id))
        }

        if (listBasicChatModel.get(0).id === last_message_id) {
            listBasicChatModel.insert(0, handleMessage(window.client.messages[channel_id as Snowflake][message as Snowflake]))
        }
    }
}

export function loadBeforeMsgId(last_msg: string) {

    console.log("loadBeforeMsgId.1 " + loading + ", " + last_msg)

    if (loading) return;
    if (cooldown) return;
    if (last_msg==null) return;

    loading = true;

    cooldown = true;
    
    // listBasicChatView.currentIndex = ttt

    console.log("cooldown.start")

    setTimeout(()=>{
        cooldown = false;
        console.log("cooldown.stop")
    }, 500)

    console.log("loadBeforeMsgId.0 " + loading + ", " + last_msg)

    window.client.messageStore.getMessageFrom(currentChat as Snowflake, last_msg as Snowflake, 30, function(data: string[]){
        loading = false;

        console.log("getMessageFrom=" + last_msg + ", " + data.length)

        if (!data.length) return

        handleClientReady(data, true)
    });
}

function loadAfterMsgId(last_msg: string) {

    console.log("loadAfterMsgId.1 " + loading_after + ", " + last_msg)

    if (loading_after) return;
    if (cooldown_after) return;
    if (last_msg==null) return;

    loading_after = true;

    cooldown_after = true;
    
    // listBasicChatView.currentIndex = ttt

    console.log("cooldown_after.start")

    setTimeout(()=>{
        cooldown_after = false;
        console.log("cooldown_after.stop")
    }, 500)

    console.log("loadAfterMsgId.0 " + loading_after + ", " + last_msg)

    window.client.messageStore.getMessageAfter(currentChat as Snowflake, last_msg as Snowflake, 30, function(data: string[]){
        loading_after = false;

        console.log("getMessageAfter=" + last_msg + ", " + data.length)

        if (!data.length) return

        handleClientReady(data, false)
    });
}

function scrollToIndex(index: number) {
    if(index > 0 && index < listBasicChatView.count) {
        listBasicChatView.positionViewAtIndex(index, ListView.Contain)
//                            currentIndex = index;
        if(index === listBasicChatView.count - 1) {
            // manuallyScrolledToBottom = true;
        }
    }
}

function handleMessageInput() {

    if (messageField2.text.length) {

        const textMessage = messageField2.text;

        messageField2.text = ""

        console.log("Send message " + textMessage + " to " + currentChat)

        sendTextMessage(currentChat, textMessage, function(err, data){
            if (err) {
                window.client.emit("debug", "Http request " + JSON.stringify(err))
                return;
            }

            const tt = JSON.parse(data as string);
            console.log("TT=" + data)

            // listGuildChatModel.append({
            //     id: tt.id,
            //     userAvatar: "",
            //     chatMessage: tt.content,
            // })

            initialScroll = true;
        })
    }
}

function onCountChanged() {
    console.log("BasicChat onCountChanged")

    console.log("initData.1="+listBasicChatView.currentIndex)
    console.log("Count="+listBasicChatView.count)

    
    const ttt = listBasicChatView.indexAt(listBasicChatView.contentX, listBasicChatView.contentY);
    console.log("IndexAt="+ttt)

    if (initialScroll) {
        initialScroll = false;

        listBasicChatView.currentIndex = 0
    }
}

function onContentYChanged() {
    // console.log("onContentYChanged " + 
    //     " currentIndex=" + listGuildChatView.currentIndex + ", " + 
    //     " count=" + listGuildChatView.count + ", " +
    //     " contentY=" + listGuildChatView.contentY + ", " + 
    //     " contentHeight=" + listGuildChatView.contentHeight + ", " +
    //     " height=" + listGuildChatView.height + ", " +
    //     " indexAt=" + indexAt(listGuildChatView.contentX, listGuildChatView.contentY) + ", " +

    //     " at_top=" + listGuildChatView.atYBeginning + ", " +
    //     " at_bot=" + listGuildChatView.atYEnd)

    if (listBasicChatModel.count==0) return

    const ttt = listBasicChatView.indexAt(listBasicChatView.contentX, listBasicChatView.contentY);
    const bottom_index = listBasicChatView.indexAt(listBasicChatView.contentX, listBasicChatView.contentY + listBasicChatView.height);

    // console.log("\n\n\nTest=[" + bottom_index + ":" + ttt + "] / " + listBasicChatView.count + "\n\n\n");


    if (ttt > 0) {
        if (ttt < 20) {
            console.log("[ChatPage] Trying to get older history items... ");
            loadAfterMsgId( listBasicChatModel.get(0).id );
        } else if (ttt > ( listBasicChatView.count - 20)) {
            console.log("[ChatPage] Trying to get newer history items... ");
            loadBeforeMsgId( listBasicChatModel.get(listBasicChatModel.count-1).id );
        }
    }

    if ((listBasicChatModel.count - ttt) > 50) {
        console.log("Remove some data from end")
        listBasicChatModel.remove(listBasicChatModel.count-10, 10)
    }

    if (bottom_index > 50) {
        console.log("Remove some data from head")
        listBasicChatModel.remove(0, 10)
    }
}


function onAtYEndChanged() {

    console.log("onAtYEndChanged " + 
                            " currentIndex=" + listBasicChatView.currentIndex + ", " + 
                            " count=" + listBasicChatView.count + ", " +
                            " contentY=" + listBasicChatView.contentY + ", " + 
                            " contentHeight=" + listBasicChatView.contentHeight + ", " +
                            " height=" + listBasicChatView.height + ", " +
                            " indexAt=" + listBasicChatView.indexAt(listBasicChatView.contentX, listBasicChatView.contentY) + ", " +

                            " at_top=" + listBasicChatView.atYBeginning + ", " +
                            " at_bot=" + listBasicChatView.atYEnd)


    // if (listGuildChatView.atYBeginning) {

    //     const ttt = listGuildChatView.indexAt(listGuildChatView.contentX, listGuildChatView.contentY);

    //     listGuildChatView.currentIndex = ttt

    //     loadBeforeMsgId();
    // }
}


function handleClientReady(data: string[], toTop: boolean) {

    const dms: BasicChat[] = data.map((msgId)=>{
        return window.client.messages[currentChat as Snowflake][msgId as Snowflake]
    })
    .map(message => handleMessage(message));

    const currentValue = listBasicChatView.count
    dms.forEach(dm => toTop ? listBasicChatModel.insert(currentValue, dm) : listBasicChatModel.insert(0, dm));
}

function padTo2Digits(num: number) {
    let number = ''+num;

    if (num < 10) number = '0' + num;

    return number;
}
  
function formatDate(date: Date) {
    return [
        padTo2Digits(date.getDate()),
        padTo2Digits(date.getMonth() + 1),
        date.getFullYear(),
    ].join('.');
}

function daysDiffs(timestamp: number): number {

    let date = new Date();
    let day = date.getDate();
    let month = date.getMonth() + 1;
    let year = date.getFullYear();

    let date0 = new Date(timestamp);
    let day0 = date0.getDate();
    let month0 = date0.getMonth() + 1;
    let year0 = date0.getFullYear();

    if (year0===year && month0===month) {
        return Math.abs(day-day0);
    }


    return -1;
}

function getDateText(timestamp: number) {  
    const date = new Date(timestamp);

    const diffs = daysDiffs(timestamp);

    let dateText = ""

    if (diffs == 1) {
        dateText = "Вчера, в "
    } else if (diffs == 0) {
        dateText = "Сегодня, в "
    } else {
        // dateText = "(diffs=" + diffs + "), "
        dateText = formatDate(date) + ", "
    }

    return dateText + date.toTimeString()
}